package com.example.multidatasource.aspect;

import com.example.multidatasource.annotation.MultiDataSource;
import com.example.multidatasource.config.DynamicDataSource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * order设置为1，需要先于事务初始化
 */
@Order(value = 1)
@Slf4j
@Aspect
@Component
@ConditionalOnProperty(name = "spring.enable.multi.datasource",havingValue = "true")
public class DataSourceAspect {
    public DataSourceAspect() {
      log.info("数据源切面开始初始化");
    }

    @Pointcut(value = "@annotation(com.example.multidatasource.annotation.MultiDataSource)")
    public void dataSourcePointCut(){
    }

    @Around(value = "dataSourcePointCut()")
    public Object aroudAdvice(ProceedingJoinPoint point) throws Exception {
        Object proceed = null;
        Signature signature = point.getSignature();
        if (!(signature instanceof MethodSignature)){
            throw new Exception("MultiDataSource注解只能用于方法上");
        }
        Object target = point.getTarget();
        Method method = target.getClass().getMethod(signature.getName(), ((MethodSignature) signature).getParameterTypes());
        MultiDataSource annotation = method.getAnnotation(MultiDataSource.class);
        if (annotation != null){
            DynamicDataSource.setDataBaseName(annotation.dbName());
            log.info("设置数据源为:{}",annotation.dbName());
        } else {
            //感觉这else永远执行不了，因为一开始就只有注解了@MultiDataSource的方法才会被代理
            DynamicDataSource.setDataBaseName("primary");
            log.info("设置数据源为默认:primary");
        }
        try {
            proceed = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            log.error(e.getMessage(),e);
        } finally {
            DynamicDataSource.clearDataBaseName();
        }
        return proceed;
    }
}
